<?php
namespace mirage\core;
if(!defined('MIRAGE_MODE')) die('Forbidden');
use mirage\Mirage;
use mirage\core\SystemException;
/**
 * Description of BaseModel
 * Date Created Aug 30, 2011 11:22:16 AM
 * @author Bryan Salazar
 */
class BaseModel {
   // default database connection
   public $db = 'db';
   public $error_messages;
   public $error_count = 0;
   private static $_dbh = null;
   


   /****************************************************************************
    * Original Author: Bryan Salazar
    * Creation Date: June 2, 2011
    * Return: array (validation)
    * Description: You should override this method to declare validation.
    *
    * Example:
    *    protected function _validation()
    *    {
    *       return array(
    *           array('fields'=>array('username','password'),
    *               'validator'=>'StringValidation',
    *           ),
    *       );
    *    }
    ***************************************************************************/
   protected function _validation()
   {
      return array();
   }

   /****************************************************************************
    * Original Author: Bryan Salazar
    * Creation Date: June 2, 2011
    * Parameter: array $attributes (attributes you want to validate)
    * Return: boolean
    * Description: Return true if there is no error else false.
    *             This method will call executeValidation($attributes)
    ***************************************************************************/
   public function isValid($attributes)
   {
      $this->executeValidation($attributes);
      if($this->error_count) {
         return false;
      }
      return true;
   }

   /****************************************************************************
    * Original Author: Bryan Salazar
    * Creation Date: June 2, 2011
    * Return: string $html
    * Description: Will display all error messages. Override this method if
    *             you want different display
    ***************************************************************************/
   public function getErrorMessages()
   {
      $html = '<ul style="color: red">';
      foreach($this->error_messages as $attribute => $message) {
         $html.='<li>' . $message . '</li>';
      }
      $html.='</ul>';
      return $html;
   }

   /****************************************************************************
    * Original Author: Bryan Salazar
    * Creation Date: June 2, 2011
    * Parameter: string $attribute (attribute you want to get error message)
    * Return: string $error
    * Description: Will display error message for this attribute
    ***************************************************************************/
   public function getAttributeErrorMessage($attribute)
   {
      return $this->error_messages[$attribute];
   }

   /****************************************************************************
    * Original Author: Bryan Salazar
    * Creation Date: June 2, 2011
    * Parameter: array $attributes
    * Description: Excute all validation for attribute define in _validation()
    ***************************************************************************/
   protected function executeValidation($attributes)
   {
      $validators = array();
      $validations = $this->_validation();
      if(MIRAGE_MODE == 'dev') {
         foreach($attributes as $attribute) {
            if(!property_exists($this, $attribute)) {
               $class_name = get_class($this);
               throw new SystemException('Model '. $class_name .' has no property ' . $attribute);
            }
         }
      }
      
      // each model attribute
      foreach($attributes as $attribute) {
         foreach($validations as $validation) {
            if(in_array($attribute, $validation['fields'])) {
               if(!isset($validators[$validation['validator']])) {
                  $validators_path = Mirage::app()->getAppPath().'/validators/';
                  if(!file_exists($validators_path . 
                          $validation['validator'] .'.php'))
                     throw new SystemException($validation['validator'] . 
                             ' not found in ' . $validators_path . 
                             $validation['validator'] .'.php');
                  include $validators_path . $validation['validator'] .'.php';
                  // create instance of validator
                  $validator = new $validation['validator'];
                  $validators[$validation['validator']] = $validator;
               } else {
                  $validator = $validators[$validation['validator']];
               }
                  
               try {
                  $options = array();
                  if(isset($validation['options'])) {
                     $options = $validation['options'];
                  }
                  
                  $validator->rules($this,$attribute,$options);
                  // catch exception throw by custom validation
               } catch(SystemException $e) {
                  $this->error_messages[$attribute] = $e->getMessage();
                  $this->error_count++;
                  break;
               }
            } // end if $attribute is in $validation['fields']
         }// end foreach $validations
      }// end foreach $attributes
   }   
   
   /****************************************************************************
    * Original Author: Bryan Salazar
    * Date Creation: May 31, 2011
    * Parameter: array (attribute name)
    * Description: Create property on the fly and assign value
    ***************************************************************************/
   public function setAttributes(array $attributes)
   {
      foreach($attributes as $key => $value) {
         if(!property_exists($this, $key)) {
            $file = realpath(dirname(__FILE__)) . '/' . __FILE__;
            throw new SystemException(get_class($this) . ' has no property "' 
                    . $key . '" in ' . $file);
         }
         $this->$key = $value;
      }
   }
   
   
   /****************************************************************************
    * Original Author: Bryan Salazar
    * Date Creation: May 31, 2011
    * Description: create instance of model, PDO and connect to database
    ***************************************************************************/
   public function __construct($isConnected=true) {
      if($isConnected) {
         if(!isset(self::$_dbh) || self::$_dbh == null) {
            $config = Mirage::app()->getConfigDb($this->db);
            try {
               self::$_dbh = new \PDO(
                                      $config['dsn'],
                                      $config['username'],
                                      $config['password']
                                   );
               self::$_dbh->setAttribute( \PDO::ATTR_ERRMODE,
                                        \PDO::ERRMODE_EXCEPTION
                                       );
            } catch(\PDOException $e) {
               throw new SystemException($e->getMessage());
            }
         }
      }
   }
   
   public function getDbh() {
      return self::$_dbh;
   }
}
